﻿using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using Blackbird.Common.Utility;
using Blackbird.Core.Editable;
using Blackbird.Studio.Context;
using Blackbird.Studio.Mvvm;
using Blackbird.Studio.ViewModel.EntityViewModels;
using Blackbird.Studio.ViewModel.Framework;
using Microsoft.Win32;

namespace Blackbird.Studio.ViewModel {
    public class MainWindowViewModel : HostViewModel {
        private const string FileFilter =
            "Editable Entity Files (*.mdl, *.spt, *.fsl, *.fst, *.fra)|*.mdl, *.spt, *.fsl, *.fst, *.fra|XML Files (*.xml)|*.xml|All Files (*.*)|*.*";

        private EditableModuleViewModel _activeModule;
        private Visibility _navigatorVisible;

        private IEntityViewModel _selectedItem;

        public MainWindowViewModel() {
            NavigatorVisible = Visibility.Collapsed;
            RegisteredCommands = new ObservableCollection<CommandViewModel>();
            CreateRegisteredCommands();
            EditSelectedItemCommand = new RelayCommand(param => EditSelectedItem());
            EditActiveModuleCommand = new RelayCommand(param => EditActiveModule());
        }

        public ObservableCollection<CommandViewModel> RegisteredCommands { get; private set; }

        public IEntityViewModel SelectedItem {
            get { return _selectedItem; }
            set {
                if (_selectedItem != value) {
                    _selectedItem = value;
                    InvokePropertyChanged("SelectedItem");
                }
            }
        }

        public CommandViewModel NewModuleCommand { get; private set; }
        public CommandViewModel OpenModuleCommand { get; private set; }
        public CommandViewModel SaveModuleCommand { get; private set; }
        public CommandViewModel SaveModuleAsCommand { get; private set; }
        public CommandViewModel CloseModuleCommand { get; private set; }

        public RelayCommand EditSelectedItemCommand { get; private set; }
        public RelayCommand EditActiveModuleCommand { get; private set; }

        public EditableModuleViewModel ActiveModule {
            get { return _activeModule; }
            set {
                if (_activeModule != value) {
                    _activeModule = value;
                    NavigatorVisible = value != null ? Visibility.Visible : Visibility.Collapsed;
                    OnActiveModuleChanged();
                    InvokePropertyChanged("ActiveModule");
                }
            }
        }

        public Visibility NavigatorVisible {
            get { return _navigatorVisible; }
            set {
                if (_navigatorVisible != value) {
                    _navigatorVisible = value;
                    InvokePropertyChanged("NavigatorVisible");
                }
            }
        }

        public IEnumerable<string> CommandCategories {
            get { return RegisteredCommands.Select(cmd => cmd.Category).Distinct(); }
        }

        public IEnumerable<string> CommandSources {
            get {
                return ActiveModule != null
                           ? ActiveModule.RegisteredCommands.Select(cmd => cmd.EntityViewModel.Entity.Name)
                           : null;
            }
        }

        protected void CreateRegisteredCommands() {
            RegisteredCommands.Add(
                NewModuleCommand = new CommandViewModel("New Module", new RelayCommand(param => NewModule())) {
                    Category = "New",
                });
            RegisteredCommands.Add(
                OpenModuleCommand = new CommandViewModel("Open Module", new RelayCommand(param => OpenModule())) {
                    Category = "Open",
                });
            RegisteredCommands.Add(
                SaveModuleCommand =
                new CommandViewModel("Save Module",
                                     new RelayCommand(param => SaveModule(),
                                                      param =>
                                                      ActiveModule != null &&
                                                      !string.IsNullOrEmpty(ActiveModule.FileName))) {
                                                          Category = "Save",
                                                      });
            RegisteredCommands.Add(
                SaveModuleAsCommand =
                new CommandViewModel("Save Module As",
                                     new RelayCommand(param => SaveModuleAs(), param => ActiveModule != null)) {
                                         Category = "Save",
                                     });
            RegisteredCommands.Add(
                CloseModuleCommand =
                new CommandViewModel("Close Module",
                                     new RelayCommand(param => CloseModule(), param => ActiveModule != null)) {
                                         Category = "Close",
                                     });
        }

        private void NewModule() {

            var newModuleViewModel = EntityModelContext.CreateViewModel<EditableModuleViewModel, EditableModule>();
            Workspaces.Add(newModuleViewModel);
            ActiveModule = newModuleViewModel;

        }

        private bool SaveOrDiscardChanges(IEntityViewModel entityViewModel) {
            if ((entityViewModel != null) && entityViewModel.IsDirty) {

            }

            if (ActiveModule != null)
                ActiveModule.CloseCommand.Execute(null);
            return true;
        }

        private void OpenModule() {
            if (SaveOrDiscardChanges(ActiveModule)) {
                var dialog = new OpenFileDialog { Filter = FileFilter };
                bool? dialogResult = dialog.ShowDialog();
                if (dialogResult == true) {
                    var newModuleViewModel =
                        EntityModelContext.CreateViewModel<EditableModuleViewModel, EditableModule>(dialog.FileName);
                    ActiveModule = newModuleViewModel;
                }
            }
        }

        private void SaveModule() {
            if (ActiveModule != null) {
                SerializationUtility.SaveToFile(ActiveModule.FileName, ActiveModule.Model);
            }
        }

        private void SaveModuleAs() {
            var dialog = new SaveFileDialog { Filter = FileFilter, DefaultExt = ".mdl" };
            if (dialog.ShowDialog() == true) {
                SerializationUtility.SaveToFile(dialog.FileName, ActiveModule.Model);
                ActiveWorkspace.FileName = dialog.FileName;
            }
        }

        private void CloseModule() {
            ActiveWorkspace.CloseCommand.Execute(null);
            ActiveModule = null;
        }

        private void OnActiveModuleChanged() {
            if (ActiveModule != null) {
                RegisteredCommands.Clear();
                CreateRegisteredCommands();
                ActiveModule.RegisteredCommands.ToList().ForEach(cmd => RegisteredCommands.Add(cmd));
            }
        }

        private void EditSelectedItem() {
            var workspace = (WorkspaceViewModel)SelectedItem;
            if (Workspaces.Contains(workspace))
                workspace.IsActive = true;
            else
                Workspaces.Add(workspace);
        }

        private void EditActiveModule() {
            var workspace = Workspaces.SingleOrDefault(ws => ws is EditableModuleViewModel) as EditableModuleViewModel;
            if (workspace == null)
                Workspaces.Add(ActiveModule);
            else
                workspace.IsActive = true;
        }

        public override void ReceiveMessage<TSender>(TSender sender, string message) {
            if (message == "IsSelected") {
                var entityViewModel = (IEntityViewModel)sender;
                if (entityViewModel != null && entityViewModel.IsSelected) {
                    SelectedItem = entityViewModel;
                }
            }
        }
    }
}